package tp_imag.service.impl;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import ij.ImagePlus;
import ij.io.FileSaver;
import ij.process.BinaryProcessor;
import ij.process.ByteProcessor;
import ij.process.ImageConverter;
import ij.process.ShortProcessor;
import tp_imag.model.ActualImage;
import org.apache.log4j.Logger;

public class BuscarPuntos {

    static Logger logger = Logger.getLogger(Recorrido.class);
    String nombreArchivo = "prueba";
    String dirArchivo = ".";
    private int minRecorrido = 50;

    /**
     * @param args
     * @throws IOException
     */
    public Vector<CoordenadaTransformada> execute(ByteProcessor source, String path) throws IOException {
        BufferedImage imagenPuntos = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        ByteProcessor bpPuntos = new ByteProcessor(imagenPuntos);
        ByteProcessor bpRecorrido = new ByteProcessor(imagenPuntos);

        int arrayImagenPuntos[][] = bpPuntos.getIntArray();
        int arrayRecorrido[][] = bpRecorrido.getIntArray();


        //cargo el arrayImage
        int arrayImagen[][] = source.getIntArray();




        int tamanoPunto = 4;
        int margenPunto = (new Double(Math.ceil(tamanoPunto / 2.0))).intValue();
        int xInicio = 0;
        int yInicio = 0;

        int puntos = 0;
        int xPrimero = 0;
        int yPrimero = 0;

        boolean primero = true;
        for (int x = xInicio; x < source.getWidth() - tamanoPunto; x++) {
            for (int y = yInicio; y < source.getHeight() - tamanoPunto; y++) {
                if (analizarPunto(x, y, arrayImagen, tamanoPunto)) {
                    arrayImagenPuntos[x][y] = 255;
                    if( (x % 7) == 0){
                        arrayImagenPuntos[x][source.getHeight() - 1 - tamanoPunto] = 255;
                    }
                    if (primero) {
                        xPrimero = x;
                        yPrimero = y;
                        primero = false;
                    }
                    puntos++;
                }
            }
        }
        //Armar Recorrido
        logger.debug("Armando Recorrido...");
        Recorrido recorrido = null;
        int intentos=0;
        //while (recorrido == null || (recorrido.getLongitud() < minRecorrido && intentos < 500)){
            recorrido = armarRecorrido(arrayImagenPuntos, arrayRecorrido, xPrimero, yPrimero, source.getWidth(), source.getHeight());    
       /*     if (recorrido.getLongitud()< minRecorrido){
                intentos++;
                logger.info("Intento recorrido nro: "+intentos);
                limpiarImagen(arrayImagenPuntos, recorrido);
                boolean keep = true;
                while (xInicio<source.getWidth() && keep){
                    while (yInicio<source.getHeight() && keep){
                        if (arrayImagenPuntos[xInicio][yInicio] == 255){
                            keep =false;
                            xPrimero = xInicio;
                            yPrimero = yInicio;
                        }
                    }
                }

            }
        }*/



        ImagePlus nueva = new ImagePlus();

        bpPuntos.setIntArray(arrayImagenPuntos);
        nueva.setProcessor(nombreArchivo + "_puntos", bpPuntos);
        ImageConverter icNuevo = new ImageConverter(nueva);
        icNuevo.convertToGray8();
        FileSaver fs = new FileSaver(nueva);
        fs.saveAsJpeg(path + "_puntos.jpg");
        logger.debug("Archivo generado: " + path + "_puntos.jpg");


        bpRecorrido.setIntArray(arrayRecorrido);
        ActualImage.getInstance().setVectorizedBP(bpRecorrido);
        ActualImage.getInstance().setVectorized(bpRecorrido.getBufferedImage());
        nueva.setProcessor(path, bpRecorrido);
        icNuevo = new ImageConverter(nueva);
        icNuevo.convertToGray8();
        fs = new FileSaver(nueva);
        fs.saveAsJpeg(path + "_puntos_recorrido.jpg");
        logger.debug("Archivo generado: " + path + "_puntos_recorrido.jpg");


        logger.debug("nro Puntos: " + puntos);
        int MAX = 300;
        //int MAX=recorrido.getPuntos().size();

        /*
         * Transformar recorrido de puntos
         */
        Vector<CoordenadaTransformada> vt = null;
        if (recorrido != null) {
            vt = transformarRecorrido(recorrido, MAX);
        }

        /*
         * AntiTransformar puntos
         */
        Vector<Coordenada> vr = null;
        arrayRecorrido = null;
        //if(vt!=null)
        //arrayRecorrido=AntiTransformarRecorrido(vt,bpRecorrido,recorrido.getPuntos().size(),MAX);

        if (arrayRecorrido != null) {
            //Armar Recorrido
            logger.debug("Armando Recorrido antitransformado ...");

            bpRecorrido.setIntArray(arrayRecorrido);
            ActualImage.getInstance().setVectorizedBP(bpRecorrido);
            nueva.setProcessor(nombreArchivo + "_puntos_recorrido_anti", bpRecorrido);
            icNuevo = new ImageConverter(nueva);
            icNuevo.convertToGray8();
            fs = new FileSaver(nueva);
            fs.saveAsJpeg(dirArchivo + "/" + nombreArchivo + "_puntos_recorrido_anti.jpg");
            logger.debug("Archivo generado: " + dirArchivo + "/" + nombreArchivo + "_puntos_recorrido_anti.jpg");
        }
        return vt;
    }


    private void limpiarImagen(int[][] arrayImagenPuntos, Recorrido recorrido){
        Vector coordenadas =recorrido.getPuntos();
        for (Object object : coordenadas) {
            Coordenada coordenada = (Coordenada) object;
            arrayImagenPuntos[coordenada.getX()][coordenada.getY()] = 0;
        }
    }

    static Recorrido armarRecorrido(int arrayOrigen[][], int arrayDestino[][], int x, int y, int ancho, int alto) {

        Recorrido recorrido = new Recorrido(arrayOrigen, ancho, alto);


        try {
            recorrido.buscar(new Coordenada(x, y));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Iterator iCoordenada = recorrido.getPuntos().iterator();
        int cuenta = 0;
        while (iCoordenada.hasNext()) {
            Coordenada punto = (Coordenada) iCoordenada.next();
            arrayDestino[punto.getX()][punto.getY()] = 255;
            cuenta++;
        }
        return recorrido;
    }

    static boolean analizarPunto(int xPuntero, int yPuntero, int arrayImagen[][], int tamanoPunto) {
        int cuentaBlancos = 0;
        int cuentaNegros = 0;
        for (int x = xPuntero; x < xPuntero + tamanoPunto; x++) {
            for (int y = yPuntero; y < yPuntero + tamanoPunto; y++) {
                if (arrayImagen[x][y] == 0) {
                    cuentaNegros++;
                } else {
                    cuentaBlancos++;
                }
            }
        }
        return Math.abs(cuentaBlancos - cuentaNegros) < 3;
    }

    public Vector<CoordenadaTransformada> transformarRecorrido(Recorrido recorrido, int MAX) throws IOException {

        /* Aca calculo la transformada de fourie sobre los puntos de recorrido
         * y arma otro array con cada uno de los puntos tranformados
         *
         * Se aplica X(n)=xn+jyn
         * X(k)=Sum(X(n)Exp(-jPikn/N) 0<=k<=N-1
         */

        Vector<CoordenadaTransformada> vt = new Vector<CoordenadaTransformada>(300);
        Vector<Coordenada> vr = recorrido.getPuntos();

        int N = recorrido.getPuntos().size();	//Cantidad de puntos de recorrido de la imagen
        double sumX = 0;						//Suma para cada k
        double sumY = 0;						//Suma para cada k
        double PI = Math.PI;
        Coordenada coordenada;

        logger.debug("Cantidad ptos recorrido" + N);

        /*
         * Los 150 primeros puntos del recorrido transformados
         */

        for (int k = 0; k < (MAX / 2); k++) {
            for (int n = 0; n < N - 1; n++) {
                coordenada = vr.get(n);
                sumX += coordenada.getX() * Math.cos((2 * PI * k * n / N)) +
                        coordenada.getY() * Math.sin((2 * PI * k * n / N));
                sumY += -coordenada.getX() * Math.sin((2 * PI * k * n / N)) +
                        coordenada.getY() * Math.cos((2 * PI * k * n / N));
            }

            CoordenadaTransformada ct = new CoordenadaTransformada(sumX, sumY);
            vt.add(ct);
            sumX = sumY = 0;
        }

        /*
         * Los 150 ultimos puntos del recorrido transformados
         */
        int AUX;
        if (MAX != N) {
            AUX = N - (MAX / 2);	//Si se calculan todos los puntos
        } else {
            AUX = MAX / 2;
        }

        for (int k = AUX; k < N; k++) {
            for (int n = 0; n < N - 1; n++) {
                coordenada = vr.get(n);
                sumX += coordenada.getX() * Math.cos((2 * PI * k * n) / N) +
                        coordenada.getY() * Math.sin((2 * PI * k * n) / N);
                sumY += -coordenada.getX() * Math.sin((2 * PI * k * n) / N) +
                        coordenada.getY() * Math.cos((2 * PI * k * n) / N);
            }

            CoordenadaTransformada ct = new CoordenadaTransformada(sumX, sumY);
            vt.add(ct);
            sumX = sumY = 0;
        }

        /*Vector transformado vt
         *
         */

        Iterator iCoordenada = vt.iterator();
        while (iCoordenada.hasNext()) {
            CoordenadaTransformada punto = (CoordenadaTransformada) iCoordenada.next();

            logger.debug("Ptos Transformados: " + punto.getX() + "--" + punto.getY());
        }

        /*
         * Serializar el vector transformado
         */
        FileOutputStream fout = new FileOutputStream(dirArchivo + "/" + nombreArchivo + "_vt.dat");
        ObjectOutputStream oos = new ObjectOutputStream(fout);

        oos.writeObject((Vector<CoordenadaTransformada>) vt);
        oos.close();

        return vt;

    }

    public int[][] AntiTransformarRecorrido(Vector<CoordenadaTransformada> vt, ByteProcessor bp, int N, int MAX) throws IOException {

        /* Aca calculo la Antitransformada de fourie sobre los puntos de recorrido transformados
         * y arma otro array con cada uno de los puntos Antitranformados
         *
         * Se aplica X(n)=xn+jyn
         * X(k)=Sum(X(n)Exp(-jPikn/N) 0<=k<=N-1
         */

        Vector<Coordenada> vr = new Vector<Coordenada>(MAX);

        double sumX = 0;						//Suma para cada k
        double sumY = 0;						//Suma para cada k
        double PI = Math.PI;
        CoordenadaTransformada coordenadat;

        logger.debug("Cantidad ptos antitransformada" + MAX);
        /*
         * Los 150 primeros puntos del recorrido transformados
         */

        for (int k = 0; k < (MAX / 2); k++) {
            for (int n = 0; n < MAX - 1; n++) {
                coordenadat = vt.get(n);
                sumX += coordenadat.getX() * Math.cos((2 * PI * k * n / N)) -
                        coordenadat.getY() * Math.sin((2 * PI * k * n / N));
                sumY += coordenadat.getX() * Math.sin((2 * PI * k * n / N)) +
                        coordenadat.getY() * Math.cos((2 * PI * k * n / N));
            }

            Coordenada c = new Coordenada((int) (sumX / N), (int) (sumY / N));
            vr.add(c);
            sumX = sumY = 0;
        }

        /*
         * Los 150 ultimos puntos del recorrido transformados
         */
        int AUX;
        if (MAX != N) {
            AUX = N - (MAX / 2);	//Si se calculan todos los puntos
        } else {
            AUX = MAX / 2;
        }

        for (int k = AUX; k < MAX; k++) {
            for (int n = 0; n < MAX - 1; n++) {
                coordenadat = vt.get(n);
                sumX += coordenadat.getX() * Math.cos((2 * PI * k * n) / N) -
                        coordenadat.getY() * Math.sin((2 * PI * k * n) / N);
                sumY += coordenadat.getX() * Math.sin((2 * PI * k * n) / N) +
                        coordenadat.getY() * Math.cos((2 * PI * k * n) / N);
            }

            Coordenada c = new Coordenada((int) (sumX / N), (int) (sumY / N));

            vr.add(c);
            sumX = sumY = 0;
        }

        /*Vector transformado vr
         *
         */

        int arrayRecorrido[][] = bp.getIntArray();
        Iterator iCoordenada = vr.iterator();

        logger.debug("Dimension: " + arrayRecorrido.length);


        while (iCoordenada.hasNext()) {
            Coordenada punto = (Coordenada) iCoordenada.next();

            //logger.debug("Ptos AntiTransformados: "+punto.getX()+"--"+punto.getY());

            if (punto.getX() > 0 && punto.getY() > 0 && punto.getX() < bp.getWidth() && punto.getY() < bp.getHeight()) {
                arrayRecorrido[punto.getX()][punto.getY()] = 120;
            }

        }
        //logger.debug("Fin ptos Antitransformados");


        return arrayRecorrido;
    }
}





